#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#include <unistd.h>

#include "abstime.h"



static struct timespec add_to_time(struct timespec t, double tm) {

   struct timespec t1;



   t1 = double_to_time(tm);

   t1.tv_sec = t1.tv_sec + t.tv_sec;

   t1.tv_nsec = t1.tv_nsec + t.tv_nsec;

   while (t1.tv_nsec >= BILLION) {

      t1.tv_nsec = t1.tv_nsec - BILLION;

      t1.tv_sec++;

   }

   return t1;

}



static int spinit (double stime) {    /* loops for stime seconds and returns */

   struct timespec tcurrent;

   double tend, tnow;

   if (stime == 0.0)

      return 0;

   if (clock_gettime(CLOCK_REALTIME, &tcurrent) == -1)

      return -1;

   tnow = time_to_double(tcurrent);

   tend = tnow + stime;

   while (tnow < tend) {

      if (clock_gettime(CLOCK_REALTIME, &tcurrent) == -1)

         return -1;

      tnow = time_to_double(tcurrent);

   }

   return 0;

}



/* ------------------------- Public functions -------------------------- */



double time_to_double(struct timespec t) {

   return t.tv_sec + t.tv_nsec/D_BILLION;

}



struct timespec double_to_time(double tm) {

   struct timespec t;



   t.tv_sec = (long)tm;

   t.tv_nsec = (tm - t.tv_sec)*BILLION;

   if (t.tv_nsec == BILLION) {

      t.tv_sec++;

      t.tv_nsec = 0;

   }

   return t;

}



void timehandler(int signo, siginfo_t* info, void *context) {

   timer_data *datap;

   static int timesentered = 0;



   timesentered++;

   datap = (timer_data *)(info->si_value.sival_ptr);

   if (timesentered >= datap->numtimes) {

      datap->exitflag = 1;

      return;

   }

   if (spinit(datap->spintime) == -1) {

      write(STDERR_FILENO, "Spin failed in handler\n", 23);

      datap->exitflag = 1;

   }

   if (datap->type == TYPE_PERIODIC)

      return;

   if (datap->type == TYPE_ABSOLUTE)

      datap->tvalue.it_value =

         add_to_time(datap->tvalue.it_value, datap->inctime);

   if (timer_settime(datap->timid, datap->flags, &datap->tvalue, NULL) == -1) {

      write(STDERR_FILENO, "Could not start timer in handler\n",33);

      datap->exitflag = 1;

   }

}


Program 9.16 timesignals.c
A program that calculates the time to receive 1000 SIGALRM signals.


#include <signal.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <sys/time.h>

#define COUNT 1000

#define MILLION 1000000L



static int count = 0;



/* ARGSUSED */

static void handler(int signo, siginfo_t *info, void *context) {

   count++;

}



int main(void) {

   struct sigaction act;

   sigset_t sigblocked, sigunblocked;

   long tdif;

   struct timeval tend, tstart;



   act.sa_flags = SA_SIGINFO;

   act.sa_sigaction = handler;

   if ((sigemptyset(&act.sa_mask) == -1) ||

       (sigaction(SIGALRM, &act, NULL) == -1)) {

      perror("Failed to set up handler for SIGALRM");

      return 1;

   }

   if ((sigemptyset(&sigblocked) == -1) ||

       (sigemptyset(&sigunblocked) == -1) ||

       (sigaddset(&sigblocked, SIGALRM) == -1) ||

       (sigprocmask(SIG_BLOCK, &sigblocked, NULL) == -1)) {

      perror("Failed to block signal");

      return 1;

   }

   printf("Process %ld waiting for first SIGALRM (%d) signal\n",

           (long)getpid(), SIGALRM);

   sigsuspend(&sigunblocked);

   if (gettimeofday(&tstart, NULL) == -1) {

      perror("Failed to get start time");

      return 1;

   }

   while (count <= COUNT)

      sigsuspend(&sigunblocked);

   if (gettimeofday(&tend, NULL) == -1) {

      perror("Failed to get end time");

      return 1;

   }

   tdif = MILLION*(tend.tv_sec - tstart.tv_sec) +

                   tend.tv_usec - tstart.tv_usec;

   printf("Got %d signals in %ld microseconds\n", count-1, tdif);

   return 0;

}


Although the timer resolution might be as large as 10 ms, signals may be processed at a much higher rate than timer signals can be generated. Program 9.16 waits for SIGALRM signals and calculates the time to receive 1000 signals after the first one arrives. You can use Program 9.17 to send signals to a process. It takes two command-line arguments: a process ID and a signal number. It sends the signals as fast as it can until the process dies. A reasonably fast machine should be able to handle several thousand signals per second.

Program 9.17 multikill.c
The multikill program continually sends signals to another process until the process dies.


#include <signal.h>

#include <stdio.h>

#include <stdlib.h>



int main(int argc, char *argv[]) {

   int pid;

   int sig;

   if (argc != 3) {

       fprintf(stderr, "Usage: %s pid signal\n", argv[0]);

       return 1;

   }

   pid = atoi(argv[1]);

   sig = atoi(argv[2]);

   while (kill(pid, sig) == 0) ;

   return 0;

}


